
package xj.graph2d.shapes.uml;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import xj.graph2d.DrawShape;
import xj.graph2d.GraphDocument;
import xj.meta.ModelElement;
import xj.model.uml.ExecutionOccurance;
import xj.model.uml.SequenceDiagram;
import xj.model.uml.UMLMessage;

public class UMLSequenceDiagramUtil {

  public static void setTiming(GraphDocument graph) {
    if (graph != null) {
      ModelElement model = graph.getModel();
      if (model instanceof SequenceDiagram) {
	List<TNode> tlist = new ArrayList<TNode>();

	collectTNodes(graph.getShapes(), tlist);
	int n = tlist.size();

	if (n > 0) {
	  Collections.sort(tlist);

	  TNode tnode0 = tlist.get(0);
	  tnode0.t = 0;
	  for (int i = 1; i < n; i++) {
	    TNode tnode = tlist.get(i);
	    if (tnode.pos <= tnode0.pos) {
	      tnode.t = tnode0.t;
	    } else {
	      tnode.t = tnode0.t + 1;
	    }
	    tnode0 = tnode;
	  }

	  for (int i = 0; i < n; i++) {
	    TNode tnode = tlist.get(i);
	    ModelElement m = tnode.shape.getModel();
	    if (tnode.kind == EXECUTION_START || tnode.kind == EXECUTION_END) {
	      if (m instanceof ExecutionOccurance) {
		ExecutionOccurance exec = (ExecutionOccurance) m;
		if (tnode.kind == EXECUTION_START) {
		  exec.setStart(tnode.t);
		} else {
		  exec.setEnd(tnode.t);
		}
	      }
	    } else if (tnode.kind == MESSAGE_START || tnode.kind == MESSAGE_END) {
	      if (m instanceof UMLMessage) {
		UMLMessage msg = (UMLMessage) m;
		if (tnode.kind == MESSAGE_START) {
		  msg.setStart(tnode.t);
		} else {
		  msg.setEnd(tnode.t);
		}
	      }
	    }
	  }
	}
      }
    }
  }

  static void collectTNodes(List<DrawShape> shapes, List<TNode> tlist) {
    for (Iterator<DrawShape> iter = shapes.iterator(); iter.hasNext();) {
      DrawShape s = iter.next();
      ModelElement m = s.getModel();
      if (m instanceof ExecutionOccurance) {
	Rectangle2D b = s.getBounds();
	tlist.add(new TNode(s, EXECUTION_START, (float) b.getY()));
	tlist.add(new TNode(s, EXECUTION_END,
	    (float) (b.getY() + b.getHeight())));
      } else if (m instanceof UMLMessage) {
	Point2D p1 = s.getEnd1();
	Point2D p2 = s.getEnd2();
	tlist.add(new TNode(s, MESSAGE_START, (float) p1.getY()));
	tlist.add(new TNode(s, MESSAGE_END, (float) p2.getY()));
      }

      if (s.getShapeCount() > 0) {
	collectTNodes(s.getShapes(), tlist);
      }
    }
  }

  static final int EXECUTION_START = 100;

  static final int EXECUTION_END = 101;

  static final int MESSAGE_START = 102;

  static final int MESSAGE_END = 103;

  static class TNode implements Comparable<TNode> {

    TNode(DrawShape shape, int kind, float pos) {
      this.shape = shape;
      this.kind = kind;
      this.pos = pos;
    }

    public int compareTo(TNode o) {
      if (o != null && pos != o.pos) {
	if (pos < o.pos) {
	  return -1;
	} else {
	  return 1;
	}
      }
      return 0;
    }

    DrawShape shape;

    int kind;

    float pos;

    int t;

  }

}
